Latest update: May 2015
In this tutorial, we’ll go over uploading to Facebook. We have already released a sample Facebook script, so instead of creating a new one we’re going to go over how it works.
Facebook.html uses javascript to redirect the user to Facebook’s OAuth service. It’s just used to get the Authentication Token.
This script is used to get the "long term" access token (the one that lasts 60 days, as opposed to only 1 hour).
First, it uses fa.request and cjson to confirm that the current access token (the 1 hour version) is still valid.
local function hasValidToken(t)
local b, c, h = fa.request {
url = 'https://graph.facebook.com/debug_token?input_token='
..t.user_access_token..'&access_token='
..t.app_access_token,
headers = {Connection = 'close'}
}
if (c == 200) then
local cjson = require("cjson")
local res = cjson.decode(b)
cjson = nil
if (res.error ~= nil) then
t.message = res.error.message
else
t.long_term = res.data.issued_at
if (res.data.error ~= nil) then
t.message = res.data.error.message
else
t.message = res.data.message
end
end
return res.data.is_valid
else
t.message = b
return false
end
end
It checks the response code (c) first, and if it’s "200" (a success) will move on to deconding the JSON response. If any of these steps fail, the user does not have a valid token, and "showAuthorizationURL()" will be called - which prints a formatted string directing the user to get a new key.
If hasValidToken returns "true", we move on to requesting the long term token. Here we again use fa.request to call facebook’s OAuth API. We pass out app’s token as well as the temporary access token, and it (should) reply with the 60 day version (which is stored and later printed for the user).
local function getLongtermToken(t)
local b, c, h = fa.request {
url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token'
..'&client_id='..t.app_id
..'&client_secret='..t.app_secret
..'&fb_exchange_token='..t.user_access_token,
headers = {Connection = 'close'}
}
if (c == 200) then
local s, e = b:find("&")
local longtermToken = b:sub(1, s - 1)
local file = io.open( t.token_fullpath, "w" )
file:write( longtermToken )
io.close( file )
file = nil
s, e = longtermToken:find("=")
-- Store the returned token
t.user_access_token = longtermToken:sub(e+1, #longtermToken)
end
end
This script manages reading the config file (facebook.cfg) for fb_get_token.lua. It returns a table (mod) containing the results.
Finally, this script uploads to Facebook. First, it waits for WiFi to be connected (waitWlanConnect()), and when it is connected goes through each folder in the upload directory and uploads them one file at a time.
LuaFileSystem is used to find and select each file (autoUpload()).
--...
--For each directory...
for aDirectory in lfs.dir("/DCIM") do
local _dir_id = tonumber(aDirectory:sub(1, 3))
-- print("DIR:"..aDirectory, lfs.attributes("/DCIM/"..aDirectory, "modification"))
if (_dir_id ~= nil and _dir_id >= lastDirectory) then
--for each file in that directory...
for aFile in lfs.dir("/DCIM/"..aDirectory) do
--Process and upload!
--...
Next, before uploading a folder it uses Facebook’s Graph API to create an album. This is done with a basic fa.request call, then it decodes the response string to get the album ID (which we need to make sure we upload to the right place).
local function createAlbum(_name, _message)
local req = {}
req["url"] = 'https://graph.facebook.com/v2.1/me/albums?access_token='..user_access_token
..'&name='..string.gsub (_name, " ", "+")
..'&message='..string.gsub (_message, " ", "+")
..'&privacy=%7B%22value%22%3A+%22SELF%22%7D'
req["method"] = 'POST'
req["headers"] = {Connection = "close"}
local b,c,h = fa.request(req)
if (c ~= 200) then
print(h, b)
return nil
end
req = nil
c, h = nil
local cjson = require("cjson")
local res = cjson.decode(b)
collectgarbage()
return res["id"]
end
Finally, each file is uploaded (uploadFile(filePath, _album_id)) using fa.request to send a POST request.
local function uploadFile(filePath, _album_id)
local boundary = '--bnfDxpKY69NKk'
local headers = {}
local place_holder = '<!--WLANSDFILE-->'
headers['Connection'] = 'close'
headers['Content-Type'] = 'multipart/form-data; boundary="'..boundary..'"'
local body = '--'..boundary..'\r\n'
..'Content-Disposition: form-data; name="source"; filename="'
..filePath..'"\r\n'
..'Content-Type: image/jpeg\r\n\r\n'
..'<!--WLANSDFILE-->\r\n'
.. '--' .. boundary .. '--\r\n'
headers['Content-Length'] =
lfs.attributes(filePath, 'size')
+ string.len(body)
- string.len(place_holder)
local args = {}
args["url"] = 'https://graph.facebook.com/v2.1/'
.._album_id..'/photos?access_token='
..user_access_token
..'&message='..filePath
args["method"] = "POST"
args["headers"] = headers
args["body"] = body
args["file"] = filePath
args["bufsize"] = 1460*10
local b,c,h = fa.request(args)
b, h = nil
collectgarbage()
if (c ~= 200) then
print(h, b)
return nil
end
return c
end
Uploading can take quite some time!
All sample code on this page is licensed under BSD 2-Clause License